package ru.ifmo.segal;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

/**
 * @author avhaliullin
 */
public class PlotDrawer extends JFrame {
    private java.util.List<Double> current;
    private int stepNum = 0;
    private final Algorithm algorithm;
    private final InitialConfig config;
    private final XYSeries series;
    private final JFreeChart chart;
    private final JButton stepButton;
    private final JButton startButton;
    private long lastUpdate;
    private final JLabel stepLabel;

    public PlotDrawer(final Algorithm algorithm, final InitialConfig config, java.util.List<Double> initialDistribution) {
        current = initialDistribution;
        this.config = config;
        this.algorithm = algorithm;

        stepButton = new JButton("Step");
        JLabel timeOutLabel = new JLabel("Timeout: ");
        final JTextField timeOutField = new JTextField("1");
        startButton = new JButton("Start");
        stepLabel = new JLabel("Step: 0");

        stepButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                executeStep(true);
            }
        });

        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                startButton.setEnabled(false);
                new Thread(new Runnable() {
                    public void run() {
                        while (stepNum < config.getTimeSegmentation().getCount()) {
                            executeStep(false);
                            try {
                                Thread.sleep(Integer.parseInt(timeOutField.getText()));
                            } catch (InterruptedException e1) {
                                //ignore
                            }
                        }
                    }
                }).start();
            }
        });
        setSize(800, 600);
        setVisible(true);

        series = new XYSeries("temperature");
        XYSeriesCollection seriesCollection = new XYSeriesCollection();
        seriesCollection.addSeries(series);
        chart = ChartFactory.createXYLineChart("Plot",
                "Distance",
                "Temperature",
                seriesCollection,
                PlotOrientation.VERTICAL,
                false,
                false,
                false);
        chart.setNotify(false);
        final ChartPanel chartPanel = new ChartPanel(chart,
                ChartPanel.DEFAULT_WIDTH,
                ChartPanel.DEFAULT_HEIGHT,
                ChartPanel.DEFAULT_MINIMUM_DRAW_WIDTH,
                ChartPanel.DEFAULT_MINIMUM_DRAW_HEIGHT,
                ChartPanel.DEFAULT_MAXIMUM_DRAW_WIDTH,
                ChartPanel.DEFAULT_MAXIMUM_DRAW_HEIGHT,
                false, // Buffered
                false, // Properties
                true, // Save
                true, // Print
                false, // Zoom
                false); // Tooltips
        Box mainBox = Box.createVerticalBox();

        Box controlBox = Box.createHorizontalBox();

        controlBox.add(stepButton);
        controlBox.add(timeOutLabel);
        controlBox.add(timeOutField);
        controlBox.add(startButton);
        controlBox.add(stepLabel);

        mainBox.add(controlBox);
        mainBox.add(chartPanel);

        add(mainBox);

        draw(initialDistribution);
    }

    private void executeStep(boolean alwaysDraw) {
        current = algorithm.step(config, stepNum++, current);
        if (alwaysDraw || lastUpdate + 150 < System.currentTimeMillis()) {
            draw(current);
            lastUpdate = System.currentTimeMillis();
        }
        if (stepNum == config.getTimeSegmentation().getCount()) {
            startButton.setEnabled(false);
            stepButton.setEnabled(false);
            draw(current);
        }
    }

    private void draw(List<Double> plot) {
        series.clear();
        for (int i = 0; i < config.getDistanceSegmentation().getCount(); i++) {
            series.add(config.getDistanceSegmentation().getValue(i), plot.get(i));
        }
        chart.setNotify(true);
        chart.setNotify(false);
        stepLabel.setText("Step: " + stepNum);
    }

}
